﻿using UnityEngine;
using UnityEditor;
using Extensions;
using System.Reflection;
using System;

namespace TC
{
    public class PortSurface : SinglePortSurface<Port>
    {
        private Color tmpColor;

        #region 端口小圆点
        private GUIStyle basicPortStyle
        {
            get
            {
                if (target.GetType().IsSubclassOf(typeof(FlowPort)))
                {
                    if (hasConnect) { return StyleProvider.FlowPortConnected; }
                    else { return StyleProvider.FlowPortNormal; }
                }
                else
                {
                    if (hasConnect) { return StyleProvider.ValuePortConnected; }
                    else { return StyleProvider.ValuePortNormal; }
                }
            }
        }
        private GUIStyle portStyle
        {
            get
            {
                GUIStyle _portStyle = new GUIStyle(basicPortStyle);
                _portStyle.fixedHeight = basicPortStyle.fixedHeight * curScale / maxScale;
                _portStyle.fixedWidth = basicPortStyle.fixedWidth * curScale / maxScale;
                return _portStyle;
            }
        }
        private Color _portColor;
        public Color portColor
        {
            get
            {
                if (_portColor == default)
                {
                    if (target.type.IsConstructedGenericType)
                    {
                        _portColor = StyleProvider.GetVariableColor(target.type.GenericTypeArguments[0]);
                    }
                    else { _portColor = StyleProvider.GetVariableColor(target.type); }
                }
                return _portColor;
            }
        }
        private Vector2 portSize;
        public Rect portRelativeRect;
        public Rect connnectRect; // todo 代替portRelativeRect
        #endregion


        #region 端口名称
        private string showName { get => target.name; }
        private GUIStyle _basicNameStyle;
        private GUIStyle basicNameStyle 
        {
            get
            {
                if(_basicNameStyle == default)
                {
                    _basicNameStyle = new GUIStyle("label");
                    _basicNameStyle.alignment = TextAnchor.MiddleCenter;
                    _basicNameStyle.margin = new RectOffset(0, 0, 0, 0);
                    _basicNameStyle.padding = new RectOffset(2, 2, 3, 3);
                    _basicNameStyle.border = new RectOffset(0, 0, 0, 0);
                    _basicNameStyle.fontSize = 12;
                    _basicNameStyle.stretchWidth = false;
                    _basicNameStyle.normal.textColor = EditorGUIUtility.isProSkin ? Color.white : Color.black;
                }
                return _basicNameStyle;
            }
        }
        private GUIStyle nameStyle;
        private Vector2 nameSize;
        #endregion


        #region 默认值
        private bool hasDefaultValue { get => target.GetType().GetField("defaultValue") != null; }
        private bool defalutValueVisible
        {
            get => hasDefaultValue && !hasConnect && 
                ( target.type.IsAssignableFrom(typeof(string))
                || target.type.IsAssignableFrom(typeof(char))
                || target.type.IsAssignableFrom(typeof(byte))
                || target.type.IsAssignableFrom(typeof(int))
                || target.type.IsAssignableFrom(typeof(float))
                || target.type.IsAssignableFrom(typeof(long))
                || target.type.IsAssignableFrom(typeof(double))
                || target.type.IsAssignableFrom(typeof(bool))
                || target.type.IsAssignableFrom(typeof(Vector2))
                || target.type.IsAssignableFrom(typeof(Vector3))
                || target.type.IsAssignableFrom(typeof(Vector4))
                );
        }
        private string showDefaultValue
        {
            get
            {
                FieldInfo fieldInfo = target.GetType().GetField("defaultValue");
                if (defalutValueVisible)
                {
                    if (target.type.IsAssignableFrom(typeof(char)))
                    {
                        return "\'" + fieldInfo.GetValue(target).ToString() + "\'";
                    }
                    else if (target.type.IsAssignableFrom(typeof(string)))
                    {
                        if (fieldInfo.GetValue(target) != null)
                        {
                            return "\"" + fieldInfo.GetValue(target).ToString() + "\"";
                        }
                        else { return "\"\""; }
                    }
                    return fieldInfo.GetValue(target).ToString();
                }
                else { return ""; }
            }
        }
        private Color defaultValueOutlineColor { get => EditorGUIUtility.isProSkin ? Color.white : Color.black; }
        private GUIStyle _basicDefaultValueStyle;
        private GUIStyle basicDefaultValueStyle
        {
            get
            {
                if (_basicDefaultValueStyle == default)
                {
                    _basicDefaultValueStyle = new GUIStyle(StyleProvider.PortDefaultValueBG);
                    _basicDefaultValueStyle.stretchHeight = true;
                    _basicDefaultValueStyle.fontSize = 12;
                    _basicDefaultValueStyle.clipping = TextClipping.Clip;
                    _basicDefaultValueStyle.alignment = TextAnchor.MiddleCenter;
                    _basicDefaultValueStyle.margin = new RectOffset(3, 3, 0, 0);
                    _basicDefaultValueStyle.padding = new RectOffset(2, 2, 2, 2);
                    _basicDefaultValueStyle.normal.textColor = EditorGUIUtility.isProSkin ? Color.white : Color.black;
                }
                return _basicDefaultValueStyle;
            }
        }
        private GUIStyle defaultValueStyle;
        private Vector2 defaultValueSize;
        private readonly float defaultValueMaxSizeX = 100f;
        #endregion


        #region 整体相关
        private Color bgColor
        {
            get
            {
                return isHovering ?
                    new Color(portColor.r, portColor.g, portColor.b, portColor.a - 0.4f) :
                    new Color(0, 0, 0, 0);
            }
        }
        private GUIStyle _basicBgStyle;
        private GUIStyle basicBgStyle
        {
            get
            {
                if(_basicBgStyle == default)
                {
                    _basicBgStyle = new GUIStyle(StyleProvider.NodeBackground);
                    _basicBgStyle.margin = new RectOffset(3, 3, 4, 4);
                    _basicBgStyle.padding = new RectOffset(0, 0, 0, 0);
                }
                return _basicBgStyle;
            }
            set { _basicBgStyle = value; }
        }
        private GUIStyle bgStyle;
        #endregion


        public PortSurface(NodeSurface parent, Port t, float curScale) : base(t)
        {
            this.parent = parent;
            this.curScale = curScale;
        }

        public PortSurface() : base(null)
        {
        }

        // 传入Node相对Graph的Rect
        public override void OnDraw(Rect nodeRect)
        {
            tmpColor = GUI.color;
            GUI.color = bgColor;
            relativeRect = GUIHelper.MarginBox(new Rect(nodeRect.position + position, size), new GUIContent(""), bgStyle);
            GUI.color = tmpColor;
            GUILayout.BeginArea(relativeRect);
            GUILayout.BeginHorizontal();
            if (target.IsInput)
            {
                GUI.color = portColor;
                GUILayout.Box("", portStyle);
                GUI.color = tmpColor;
                ResetPortRect();
                GUILayout.Box(showName, nameStyle);
                if (defalutValueVisible)
                {
                    tmpColor = GUI.color;
                    GUI.color = defaultValueOutlineColor;
                    GUILayout.Box(showDefaultValue, defaultValueStyle, GUILayout.MaxWidth(defaultValueSize.x), GUILayout.ExpandWidth(false));
                    GUI.color = tmpColor;
                }
            }
            else
            {
                if (defalutValueVisible)
                {
                    tmpColor = GUI.color;
                    GUI.color = defaultValueOutlineColor;
                    GUILayout.Box(showDefaultValue, defaultValueStyle);
                    GUI.color = tmpColor;
                }
                GUILayout.Box(showName, nameStyle);
                GUI.color = portColor;
                GUILayout.Box("", portStyle);
                GUI.color = tmpColor;
                ResetPortRect();
            }
            GUILayout.EndHorizontal();
            GUILayout.EndArea();

            if (isHovering)
            {
                EditorGUIUtility.AddCursorRect(relativeRect, MouseCursor.Arrow);
            }
        }

        public void ResetPortRect()
        {
            if (Event.current.type == EventType.Repaint)
            {
                portRelativeRect = GUILayoutUtility.GetLastRect();
                portRelativeRect.position += relativeRect.position;
            }
        }

        public override void RefreshStyle()
        {
            nameStyle = new GUIStyle(basicNameStyle);
            nameStyle.fontSize = (int)Mathf.Floor(basicNameStyle.fontSize * curScale / maxScale);
            if (nameStyle.fontSize <= 0) { nameStyle.fontSize = 1; }
            nameStyle.padding = basicNameStyle.padding.Multiply(curScale / maxScale);
            nameStyle.margin = basicNameStyle.margin.Multiply(curScale / maxScale);

            defaultValueStyle = new GUIStyle(basicDefaultValueStyle);
            defaultValueStyle.fontSize = (int)Mathf.Floor(basicDefaultValueStyle.fontSize * curScale / maxScale);
            if (defaultValueStyle.fontSize <= 0) { defaultValueStyle.fontSize = 1; }
            defaultValueStyle.padding = basicDefaultValueStyle.padding.Multiply(curScale / maxScale);
            defaultValueStyle.margin = basicDefaultValueStyle.margin.Multiply(curScale / maxScale);

            bgStyle = new GUIStyle(basicBgStyle);
            bgStyle.padding = basicBgStyle.padding.Multiply(curScale / maxScale);
            bgStyle.margin = basicBgStyle.margin.Multiply(curScale / maxScale);
        }

        public override void RefreshSize()
        {
            portSize = new Vector2(portStyle.fixedWidth, portStyle.fixedHeight);
            nameSize = nameStyle.CalFullSize(showName);
            defaultValueSize = defaultValueStyle.CalFullSize(showDefaultValue);
            if (defaultValueSize.x > defaultValueMaxSizeX * curScale / maxScale) { defaultValueSize.x = defaultValueMaxSizeX * curScale / maxScale; }

            Vector2 contentSize;
            if (defalutValueVisible)
            {
                contentSize = new Vector2(portSize.x + nameSize.x + defaultValueSize.x,
                                 Mathf.Max(Mathf.Max(portSize.y, nameSize.y), Mathf.Max(nameSize.y, defaultValueSize.y)));
            }
            else
            {
                contentSize = new Vector2(portSize.x + nameSize.x,
                                 (portSize.y > nameSize.y) ? portSize.y : nameSize.y);
            }
            size = bgStyle.CalBoundSize(contentSize);
        }

        #region
        public bool hasConnect = false;

        public bool CanConnect(PortSurface p)
        {
            return target.CanConnect(p.target);
        }

        public virtual void OnConnect()
        {
            hasConnect = true;
            (parent as FlowNodeSurface).RefreshAppearance();
        }

        public virtual void OnDisconnect()
        {
            hasConnect = false;
            (parent as FlowNodeSurface).RefreshAppearance();
        }
        #endregion
    }
}